#pragma once
namespace treduce {
template <typename T0, typename T1>
struct add_result {
  typedef decltype((T0)0 + (T1)0) type;
};
template <typename T0, typename T1>
using add_type = typename add_result<T0, T1>::type;
template <typename T0, typename... Ts>
struct sum_result {
  typedef add_type<T0, typename sum_result<Ts...>::type> type;
};
template <typename T0>
struct sum_result<T0> {
  typedef T0 type;
};
template <typename... Ts>
using sum_type = typename sum_result<Ts...>::type;
template <typename T>
__always_inline constexpr T sum(T first) {
  return first;
}
template <typename T, typename... Ts>
__always_inline constexpr sum_type<T, Ts...> sum(T first, Ts... args) {
  return first + sum(args...);
}

template<typename T>
__always_inline constexpr T addsub(T last) {
  return last;
}
template <typename T, typename... Ts>
__always_inline constexpr sum_type<T, Ts...> addsub(T first, Ts... args) {
  auto rest = addsub(args...);
  return first - rest;
}
template<typename T>
__always_inline constexpr T max(T first) {
  return first;
}
template<typename T, typename... Ts>
__always_inline constexpr sum_type<T, Ts...> max(T first, Ts... args) {
  sum_type<Ts...> rest = max(args...);
  return first > rest ? first : rest;
}
}; // namespace treduce